iJS CONFERENCE Blog

What's New in Next.js 14?

Summarizing the JavaScript framework’s new features

Jan 17, 2024

Without a doubt, the Next.js JavaScript framework is generating the most attention in the front-end world. It remains to be seen if this attention is entirely positive, but undeniable progress is currently unfolding in this domain. In this article, we’ll examine the newest version, Next.js 14.

Why is Next.js so popular?

 

Version 14 is the first major release since the Next team published the App Router as a stable part of the framework in version 13.4. Why is Next so popular? Afterall, Next is relatively old for a JavaScript framework, initial releasing back in October 2016. 

 

Next has always aimed to simplify React application development, especially when it comes to interaction with the server side. Although React supports server-side rendering with _ReactDOMServer_, a custom implementation based on a Node.js application that renders React components on the server side and sends the generated HTML to the client is anything but convenient. Next made this and similar features easy to use and available to a wider audience. The current release adds many stabilizations and features to Next. In the following, we’ll take a closer look at what this means for us.

 

:::div {.box}

Next.js 14: Summarizing the new features

  • Static rendering server components at build time significantly improves performance.
  • Server actions enable write access to the server and can be triggered with _form_ elements or _startTransition_ function.
  • Introduces Turbopack as a separate build tool in Rust for improved performance; up to 95% faster code updates with Fast Refresh.
  • New interface between static prerendering and dynamic on-demand rendering through partial prerendering.
  • React’s Suspense component and Next’s streaming feature for efficient rendering of static and dynamic content.
  • Planned replacement of Webpack for better developer experience.

:::

 

iJS Newsletter

Keep up with JavaScript’s latest news!

The App Router – Entering a new era

 

The Next team introduced the App Router as a beta extension in version 13, and by version 13.4, the feature achieved stability. The App Router marks a paradigm shift working with Next, since the App Router uses React Server Components by default. These components are exclusively rendered on the server-side and no longer maintain their local state or ability to influence the component’s lifecycle. Furthermore, React Server Components don’t allow any user interaction. These restrictions are offset by two crucial features. Server Components can handle asynchronous operations, unlike Client Components, and can access server-side APIs.  It might sound abstract at first, but it becomes clear with a specific example.

 

:::div {.codelisting}

Listing 1: Data fetching in a server component

“`javascript

import { getAllTodos } from ‘./lib/todo.api’;

export default async function List() {

  const todos = await getAllTodos();

  <div>

    {todos.map((todo) => (

      <div key={todo.id}>{todo.title}</div>

    ))}

  </div>;

}

“`

:::

 

You can implement a server component as an _async_ function and use the _await_ keyword in the component function. Access to server-side APIs means you can access Node.js’ entire functional scope. This means you can access the file system and databases or web services, all from a React component. The advantage is that you don’t have to hide it behind a combination of _useEffect_ and _useState_. Next performs all operations on the server side, making sure that the rendering process is carried out.

 

Another special Next feature is that the server components are rendered by default at build time. This process, known as static rendering, prepares the server-side structures before a client request and sends only the finished HTML to the client. Performance is similar to a conventional static web server. 

 

But for dynamic content, this type of rendering is only available to a limited extent. There are some cases where you will render dynamically instead of statically. This is especially true if you use dynamic functions like cookies or headers, search parameters, or if you deliberately switch off caching http requests. Regardless of whether you want to use static or dynamic rendering, Next.js optimizes read access to data in both cases.

 

Up until now, when it came to writing you were on your own. Writing accesses usually had to be handled via client components and the browser’s fetch API or additional libraries. These could then be received with Next.js and its API routes and handled accordingly. 

 

With the _revalidatePath_ and _revalidateTag_ functions, Next gives us the option of rebuilding static content when changes are made, combining the advantages of static rendering and dynamic content. In version 14, Next’s Server Actions are stable and there’s now another tool that supports write access in your application.

EVERYTHING AROUND ANGULAR

The iJS Angular track

 

Server Actions in Next.js

 

Hardly any other Next feature attracted as much recent attention as Server Actions. This is due to a presentation of Next Server Actions, where a write SQL access was turned directly into a button component. The concept of Server Actions actually allows write accesses to be triggered from a component. There are three ways to trigger a server action:

 

  • In the _action attribute_ of a _form element’s _action: The server action is executed when the form is submitted.
  • Alternatively, you can use the _formAction_ attribute in buttons or input elements.
  • The third option is using the _startTransition_ function: Here, you’re independent of a form.

 

As the name suggests, Server Actions execute Next on the server side. The client sends a request to the server and the server processes the message and responds accordingly. Listing 2 shows a simple example of how to mark a to-do as read in a to-do list with Server Actions.

 

:::div {.codelisting}
Listing 2: Writing operations with server actions
“`javascript

import { revalidatePath } from ‘next/cache’;

import { getAllTodos } from ‘./lib/todo.api’;

export default async function List() {

  const todos = await getAllTodos();

  return (

    <div>

      {todos.map((todo) => (

        <form

          key={todo.id}

          action={async () => {

            ‘use server’;

            await fetch(`http://localhost:3001/todos/${todo.id}`, {

              method: ‘PUT’,

              headers: {

                ‘Content-Type’: ‘application/json’,

              },

              body: JSON.stringify({ …todo, done: !todo.done }),

            });

            revalidatePath(‘/’);

          }}

        >

          {todo.title}

          <button>{todo.done ? ‘done’ : ‘todo’}</button>

        </form>

      ))}

    </div>

  );

}

“`

:::

 

In the example, there is a list of to-dos. Each data record is enclosed in a form whose _action_ attribute contains a server action. In the simplest case, this is an asynchronous function containing the character string “use server”. This lets Next handle the form correctly. 

 

In the example, the code displays the data record title and a button. When the button is clicked, the form is sent and the Server Action activates. The browser sends a request to the next backend and executes the Server Action. In the server-side function, you can access the data record and, like in the example, send the data record to a REST API to persist the data. Then, the _revalidatePath_ function is called to update the data. This causes Next to rebuild the server-side statically generated data. You can see the updated data in the browser.

 

This Next feature closes the circle of read and write operations on the server. However, server components and Server Actions weren’t invented by the Next team; they’re actually React features. Next integrates these features into the framework so that both can be used without any extra effort.

 

Server Actions are a big topic in Next 14, but not the only one. Another innovation concerns the build process of the framework.

 

Turbopack in Next.js

 

Like many other frameworks, Next relied on Webpack as a build tool. For a long time, Webpack was the first choice for build tools in client-side JavaScript applications. But there’s been a recent surge of challengers such as Rollup or esbuild. 

 

Vercel, the company behind Next, is launching its own webpack challenger, Turbopack. Turbopack follows the strategy of some modern JavaScript tools and is not implemented in JavaScript or TypeScript, but in Rust instead. The programming language choice gives even better performance. According to Vercel, they saw significant improvements for vercel.com, a relatively extensive Next applications:

 

  • Local server startup time is 53% faster.
  • Code updates with Fast Refresh are up to 95% faster.

 

Although Turbopack is currently still in beta, it can already be used in Next with the _–turbo_ option. The Turbopack team is actively working on passing all automated tests for Next, and currently has a success rate of 90%. Once all tests are cleared, Turbopack will be considered stable. Unlike Webpack, which can be used for almost any library and framework, Turbopack development focuses on supporting Next. In the medium-term, this tool will replace the currently used Webpack in Next and give better developer experience and faster builds.

 

Partial pre-rendering

 

Next supports both static pre-rendering content and dynamic on-demand rendering. But there’s gradations in-between, where part of the displayed page is rendered statically and certain content is rendered on-demand. These options can already be used, but in a less convenient way. With the new partial pre-rendering, Next created an interface to fulfill this requirement without any extra adjustments in your application.

 

At the heart of this approach lies React’s Suspense component. Next can efficiently render the outer frame around the Suspense Boundary statically. For the Suspense component, first the framework renders the fallback content and then later inserts the dynamic content into place. This seamless transition is facilitated by Next’s streaming feature, letting the server-generated content be streamed seamlessly over the same HTTP connection, minimizing overhead.

 

What’s next for Next?

 

Next’s rapid development brought significant advancements, but it’s also been accompanied by occasional issues and instability. Despite these challenges, the Next team is working diligently to quickly address shortcomings. Moreover, the release notes for each iteration are remarkably detailed and informative.

 

Even minor releases contain a large number of bug fixes that improve the framework’s overall stability. Given Next’s pivotal role in advancing the React ecosystem and its position as a technology pioneer, it’s not surprising for occasional glitches to arise.

 

One of Next’s biggest advantages is the flexibility it gives developers to choose the right interface. While the new App Router offers enhanced features and capabilities, you don’t have to adopt it immediately. Developers can still rely on the tried-and-tested Pages Router, renowned for its stability. For example, even with the new App Router, you have the choice of using Server Actions. You can also send requests from the client to the server as usual instead.

 

The Next team firmly established a consistent approach of releasing new features, gathering community feedback , and integrating insights into updates. I highly recommend you take the chance to explore and incorporate these new features to stay ahead of the curve and harness Next’s full potential.

Sign up for the iJS newsletter and stay tuned to the latest JavaScript news!

 

BEHIND THE TRACKS OF iJS

JavaScript Practices & Tools

DevOps, Testing, Performance, Toolchain & SEO

Angular

Best-Practises with Angular

General Web Development

Broader web development topics

Node.js

All about Node.js

React

From Basic concepts to unidirectional data flows